

import { Logger } from "../utils/Logger";
import { ProtoUtils } from "../socketserver/protocol/ProtoUtils";
import { ProtoConfig } from "../socketserver/protocol/ProtoConfig";
import { SocketMsg } from "../socketserver/socket/SocketMsg";
import SocketRequestData from "./SocketRequestData";
import { SocketClientReqManager } from "./SocketClientReqManager";

const ws = require("ws");


export class WebSocketClient {

    private ws;
    private isConnecting:boolean;
    private isConnected: boolean;
    private requestMsgQue: Array<SocketRequestData> = [];

    private reqId: number = 1;
    public id: number;
    public url: string;

    private static count: number = 0
    private respCheckQue: Array<SocketRequestData> = [];

    public init(url: string, id: number) {
        if (!this.isConnected && !this.isConnecting) {
            this.isConnecting = true
            this.url = url;
            this.id = id;
            this.ws = new ws(url);
            Logger.log("WebSocketClient===init=", url, this.id)
            // this.ws = new ws('ws://192.168.0.108:8000');
            this.ws.on('open', () => {
                WebSocketClient.count++;
                this.isConnecting = false;
                Logger.info("ws onConnect===", this.url, this.id, WebSocketClient.count);
                this.isConnected = true;
                this.checkSendPack();
            });
            this.ws.on('message', (socketData) => {
                this.onGameMsg(socketData)
            })
            this.ws.on("error", (err) => {
                this.isConnected = false;
                this.isConnecting = false;
                Logger.error("WebSocketClient error=====", this.id, err)
            });
            this.ws.on('close', () => {
                this.isConnected = false;
                this.isConnecting = false;
                Logger.info('disconnected', this.id, this.url);
            });
        }
    }

    private onGameMsg(socketData: ArrayBuffer) {
        try {
            let byteArray: Uint8Array = new Uint8Array(socketData);
            let totalPack = ProtoUtils.DeserializeBinary(ProtoConfig.PB_MESSAGE, byteArray);
            let reqId: number = totalPack.getSeq();
            let protoType: number = totalPack.getHead();
            let protoData = totalPack.getData();
            let protoName: string = ProtoConfig.getProtoReqName(protoType);
            let msg: SocketMsg = SocketMsg.createSocketMsg(reqId, protoType, protoName, protoData);
            let sockeRequestData: SocketRequestData = this.getRespCheck(reqId);
            Logger.log("onGameMsg===", reqId, protoName, this.respCheckQue, sockeRequestData);
            if (sockeRequestData && sockeRequestData.callback) {
                sockeRequestData.callback(msg, this);
            }else{
                SocketClientReqManager.instance.onSocketMsg(msg, this)
            }
        } catch (error) {
            Logger.error("onGameMsg======error==", error);
        }
    }

    private getRespCheck(reqId: number) {
        for (let i = 0; i < this.respCheckQue.length; i++) {
            let resp: SocketRequestData = this.respCheckQue[i];
            if (resp.id == reqId) {
                this.respCheckQue.splice(i, 1);
                return resp;
            }
        }
    }

    public sendProto(protoPack, callback: Function = null) {
        let reqData: SocketRequestData = new SocketRequestData();
        reqData.id = this.reqId;
        this.reqId++;
        reqData.data = protoPack;
        reqData.callback = callback;
        this.requestMsgQue.push(reqData);
        if (this.isConnected) {
            this.checkSendPack();
        } else {
            this.init(this.url, this.id);
        }
    }

    private checkSendPack() {
        if (this.requestMsgQue.length > 0) {
            if (this.isConnected) {
                let socketData: SocketRequestData = this.requestMsgQue.shift();
                let serialdata: Uint8Array = this.createSendPack(socketData);
                let arrayBuffer: ArrayBuffer = serialdata.buffer;
                this.respCheckQue.push(socketData);
                this.send(arrayBuffer);
                this.checkSendPack();
            }
        }
    }

    /**
    * 创建发送包
    * @param protoPack 
    */
    private createSendPack(socketData: SocketRequestData): Uint8Array {
        let protoName: string = ProtoUtils.GetProtoName(socketData.data);
        let protoType: number = ProtoConfig.getProtoRequestType(protoName);
        let serialdata: Uint8Array = socketData.data.serializeBinary();
        let totalPack = ProtoUtils.Create(ProtoConfig.PB_MESSAGE);
        totalPack.setSeq(socketData.id);
        totalPack.setHead(protoType);
        totalPack.setData(serialdata);
        Logger.log("createSendPack==", socketData);
        return totalPack.serializeBinary();
    }

    private send(data) {
        if (this.isConnected) {
            this.ws.send(data);
        }
    }
}